package com.ssky.bean.validator.core;

import com.ssky.bean.validator.BeanValidator;
import com.ssky.bean.validator.core.checker.IChecker;
import com.ssky.bean.validator.core.exception.VldException;
import com.ssky.bean.validator.core.rule.Field;
import com.ssky.bean.validator.util.DefinerUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * @Author: ssky
 * @Date: 2021/07/25
 * @Description:
 */
public class FieldValidator<L, B> {
    public static final Logger L = LoggerFactory.getLogger(BeanValidator.class);

    private final Field field;

    private final List<IChecker<?, ?, ?>> checkers;
    private final List<FieldValidator<?, ?>> fieldValidators;

    private final boolean previousIsCollt;
    private final boolean vIsCollt;

    private IFieldValueGetter fieldValueGetter;

    public FieldValidator(Field field) {
        this.field = field;
        this.checkers = new ArrayList<>();
        this.fieldValidators = new ArrayList<>();
        this.vIsCollt = DefinerUtils.isCollection(field.getClassType());
        this.previousIsCollt = DefinerUtils.isCollection(field.getPreField());
    }

    public void validate(final L l, final B b, final IValidatorContext context, final List<Feedback> fbs) throws VldException {
        Object v = null;
        if (!b.getClass().equals(this.field.getClassType())) {
            if (!this.previousIsCollt) {
                v = fieldValueGetter.getV(l);
            } else {
                v = l;
            }
        } else {
            v = b;
        }

        for (IChecker ck : checkers) {
            Feedback fb = ck.check(v, l, b, context);
            if (fb == null)
                continue;
            if (fb.isErr()) {
                fbs.add(fb);
            }
            if (fbs.size() > context.getMaxErrCount()) {
                return;
            }
        }

        if (!this.vIsCollt) {
            for (FieldValidator fv : fieldValidators) {
                try {
                    fv.validate(v, b, context, fbs);
                } catch (RuntimeException e) {
                    L.error("fieldValidator field(" + fv.getField().getName() + ") validate method execute occur excepiton -->", e);
                    throw new VldException("fieldValidator field(" + fv.getField().getName() + ") validate method execute occur excepiton -->", e.getMessage());
                }
            }
        } else {
            if (v == null) {
                return;
            }
            Collection<?> cs = (Collection<?>) v;
            for (Object c : cs) {
                for (FieldValidator f : fieldValidators) {
                    try {
                        f.validate(c, b, context, fbs);
                    } catch (RuntimeException e) {
                        L.error("fieldValidator field(" + f.getField().getName() + ") validate method execute occur excepiton -->", e);
                        throw new VldException("fieldValidator field(" + f.getField().getName() + ") validate method execute occur excepiton -->", e.getMessage());
                    }
                }
            }
        }
    }

    public Field getField() {
        return field;
    }

    public void setFieldValueGetter(IFieldValueGetter fieldValueGetter) {
        this.fieldValueGetter = fieldValueGetter;
    }

    public IFieldValueGetter getFieldValueGetter() {
        return fieldValueGetter;
    }

    public void addCheckers(List<IChecker<?, ?, ?>> checkers) {
        if (!CollectionUtils.isEmpty(checkers)) {
            this.checkers.addAll(checkers);
        }
    }

    public void addFieldValidator(FieldValidator<?, ?> fieldValidator) {
        if (null != fieldValidator) {
            this.fieldValidators.add(fieldValidator);
        }
    }

    public void addFieldValidators(List<FieldValidator<?, ?>> fieldValidators) {
        if (!CollectionUtils.isEmpty(fieldValidators)) {
            this.fieldValidators.addAll(fieldValidators);
        }
    }

}
